﻿namespace System.ServiceModel.DomainServices.Client
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel.DataAnnotations;
    using System.Globalization;
    using System.Linq;

    public sealed class EntityChangeSet : IEnumerable<Entity>, IEnumerable
    {
        private ReadOnlyCollection<Entity> _addedEntities;
        private IEnumerable<ChangeSetEntry> _changeSetEntries;
        private ReadOnlyCollection<Entity> _modifiedEntities;
        private ReadOnlyCollection<Entity> _removedEntities;

        internal EntityChangeSet(ReadOnlyCollection<Entity> addedEntities, ReadOnlyCollection<Entity> modifiedEntities, ReadOnlyCollection<Entity> removedEntities)
        {
            if (addedEntities == null)
            {
                throw new ArgumentNullException("addedEntities");
            }
            if (modifiedEntities == null)
            {
                throw new ArgumentNullException("modifiedEntities");
            }
            if (removedEntities == null)
            {
                throw new ArgumentNullException("removedEntities");
            }
            this._addedEntities = addedEntities;
            this._removedEntities = removedEntities;
            this._modifiedEntities = modifiedEntities;
        }

        public IEnumerable<ChangeSetEntry> GetChangeSetEntries()
        {
            if (this._changeSetEntries == null)
            {
                this._changeSetEntries = ChangeSetBuilder.Build(this);
            }
            return this._changeSetEntries;
        }

        IEnumerator<Entity> IEnumerable<Entity>.GetEnumerator()
        {
            return this.AddedEntities.Concat<Entity>(this.ModifiedEntities).Concat<Entity>(this.RemovedEntities).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<Entity>) this).GetEnumerator();
        }

        public override string ToString()
        {
            return string.Format(CultureInfo.CurrentCulture, "{{Added = {0}, Modified = {1}, Removed = {2}}}", new object[] { this._addedEntities.Count, this._modifiedEntities.Count, this._removedEntities.Count });
        }

        internal bool Validate(ValidationContext validationContext)
        {
            bool flag = true;
            foreach (Entity entity in (IEnumerable<Entity>) this)
            {
                entity.VerifyNotEditing();
                bool requiresValidation = entity.MetaType.RequiresValidation;
                EntityAction action = entity.EntityActions.SingleOrDefault<EntityAction>();
                if ((requiresValidation || (action != null)) && (entity.EntityState != EntityState.Deleted))
                {
                    List<ValidationResult> validationResults = new List<ValidationResult>();
                    if (requiresValidation)
                    {
                        ValidationUtilities.TryValidateObject(entity, validationContext, validationResults);
                    }
                    if (action != null)
                    {
                        object[] parameters = action.HasParameters ? action.Parameters.ToArray<object>() : null;
                        ValidationContext context = ValidationUtilities.CreateValidationContext(entity, validationContext);
                        ValidationUtilities.TryValidateCustomUpdateMethodCall(action.Name, context, parameters, validationResults);
                    }
                    if (validationResults.Count > 0)
                    {
                        IEnumerable<ValidationResult> enumerable = (from err in validationResults select new ValidationResult(err.ErrorMessage, err.MemberNames)).Distinct<ValidationResult>(new ValidationResultEqualityComparer()).ToList<ValidationResult>().AsReadOnly();
                        ValidationUtilities.ApplyValidationErrors(entity, enumerable);
                        flag = false;
                        continue;
                    }
                    entity.ValidationErrors.Clear();
                }
            }
            return flag;
        }

        public ReadOnlyCollection<Entity> AddedEntities
        {
            get
            {
                return this._addedEntities;
            }
            internal set
            {
                this._addedEntities = value;
            }
        }

        public bool IsEmpty
        {
            get
            {
                if (((this._addedEntities == null) || (this._addedEntities.Count == 0)) && ((this._removedEntities == null) || (this._removedEntities.Count == 0)))
                {
                    if (this._modifiedEntities != null)
                    {
                        return (this._modifiedEntities.Count == 0);
                    }
                    return true;
                }
                return false;
            }
        }

        public ReadOnlyCollection<Entity> ModifiedEntities
        {
            get
            {
                return this._modifiedEntities;
            }
            internal set
            {
                this._modifiedEntities = value;
            }
        }

        public ReadOnlyCollection<Entity> RemovedEntities
        {
            get
            {
                return this._removedEntities;
            }
            internal set
            {
                this._removedEntities = value;
            }
        }
    }
}

